using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;

namespace FileSearcher
{
	public partial class MainForm : Form
	{
		private CancellationTokenSource _cts;
		private readonly object _lock = new object();
		private readonly List<FileItem> _allFiles = new List<FileItem>();
		private string _currentSort = "Name";
		private bool _sortAscending = true;
		private const int MAX_FILES = 10000; // 最大文件数量限制
		private int _accessDeniedCount = 0; // 记录访问被拒绝的目录数量
		private int _otherErrorCount = 0; // 记录其他错误的数量

		public MainForm()
		{
			InitializeComponent();
			// 初始化过滤框水印
			txtFilter_Leave(null, null);
		}

		private void btnBrowse_Click(object sender, EventArgs e)
		{
			using (var dialog = new FolderBrowserDialog())
			{
				DialogResult dr = dialog.ShowDialog(this);
				if (dr == DialogResult.OK && !string.IsNullOrEmpty(dialog.SelectedPath))
				{
					txtDirectory.Text = dialog.SelectedPath;
				}
			}
		}

		private void btnStart_Click(object sender, EventArgs e)
		{
			if (string.IsNullOrEmpty(txtDirectory.Text) || !Directory.Exists(txtDirectory.Text))
			{
				MessageBox.Show(this, "请选择有效的目录。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
				return;
			}

			// 先快速估算文件数量
			lblStatus.Text = "正在估算文件数量...";
			Application.DoEvents();

			Task.Run(() =>
			{
				try
				{
					int estimatedCount = EstimateFileCount(txtDirectory.Text);
					
					this.Invoke(new Action(delegate
					{
						if (estimatedCount > MAX_FILES)
						{
							var result = MessageBox.Show(
								$"您选择的目录包含约 {estimatedCount} 个文件，超过最大限制 {MAX_FILES} 个文件。\n\n" +
								"继续扫描可能会导致程序响应缓慢。\n\n" +
								"是否仍要继续扫描？",
								"文件数量过多",
								MessageBoxButtons.YesNo,
								MessageBoxIcon.Warning);
							
							if (result == DialogResult.No)
							{
								lblStatus.Text = "就绪";
								return;
							}
						}
						
						StartScanning();
					}));
				}
				catch (Exception ex)
				{
					this.Invoke(new Action(delegate
					{
						MessageBox.Show(this, "估算文件数量时发生错误：" + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
						lblStatus.Text = "就绪";
					}));
				}
			});
		}

		private void StartScanning()
		{
			btnStart.Enabled = false;
			btnStop.Enabled = true;
			progress.Visible = true;
			lblStatus.Text = "正在扫描...已找到 0 个文件";
			_allFiles.Clear();
			lvFiles.Items.Clear();
			lvStats.Items.Clear();
			chartTypes.Series[0].Points.Clear();
			_accessDeniedCount = 0; // 重置错误计数
			_otherErrorCount = 0;

			_cts = new CancellationTokenSource();
			CancellationToken token = _cts.Token;

			// 使用现代的异步方法
			Task.Run(async () =>
			{
				try
				{
					await ScanDirectoryAsync(txtDirectory.Text, token);
					
					// 扫描完成
					this.Invoke(new Action(delegate
					{
						ApplyFilterAndRender();
						string statusMessage = "扫描完成，共找到 " + _allFiles.Count + " 个文件";
						
						// 如果有错误，添加错误信息
						if (_accessDeniedCount > 0 || _otherErrorCount > 0)
						{
							statusMessage += " (";
							if (_accessDeniedCount > 0)
							{
								statusMessage += $"无法访问 {_accessDeniedCount} 个目录";
							}
							if (_otherErrorCount > 0)
							{
								if (_accessDeniedCount > 0) statusMessage += ", ";
								statusMessage += $"其他错误 {_otherErrorCount} 个";
							}
							statusMessage += ")";
						}
						
						lblStatus.Text = statusMessage;
						ResetUiAfterFinish();
						
						// 显示错误摘要
						if (_accessDeniedCount > 0)
						{
							MessageBox.Show(this, 
								$"扫描过程中，有 {_accessDeniedCount} 个目录无法访问（权限不足或其他原因）。\n\n" +
								"您可能需要以管理员身份运行程序来访问这些目录。\n\n" +
								$"已找到的 {_allFiles.Count} 个文件已显示在列表中。", 
								"扫描完成 - 部分目录无法访问", 
								MessageBoxButtons.OK, 
								MessageBoxIcon.Information);
						}
					}));
				}
				catch (OperationCanceledException)
				{
					// 用户取消
					this.Invoke(new Action(delegate
					{
						lblStatus.Text = "扫描已停止，共找到 " + _allFiles.Count + " 个文件";
						ResetUiAfterFinish();
					}));
				}
				catch (Exception ex)
				{
					// 发生错误
					this.Invoke(new Action(delegate
					{
						string friendlyMessage = GetFriendlyErrorMessage(ex);
						MessageBox.Show(this, friendlyMessage, "扫描错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
						ResetUiAfterFinish();
					}));
				}
			}, token);
		}

		private int EstimateFileCount(string root)
		{
			int count = 0;
			var stack = new Stack<string>();
			stack.Push(root);
			
			while (stack.Count > 0 && count < MAX_FILES * 2) // 估算时也设置上限
			{
				var current = stack.Pop();
				try
				{
					var dirs = Directory.GetDirectories(current);
					foreach (var dir in dirs) stack.Push(dir);
					
					var files = Directory.GetFiles(current);
					count += files.Length;
				}
				catch
				{
					// 忽略无法访问的目录
				}
			}
			
			return count;
		}

		private void btnStop_Click(object sender, EventArgs e)
		{
			if (_cts != null && !_cts.IsCancellationRequested)
			{
				_cts.Cancel();
				lblStatus.Text = "正在停止扫描...";
			}
		}

		private void txtFilter_TextChanged(object sender, EventArgs e)
		{
			ApplyFilterAndRender();
		}

		private void txtFilter_Enter(object sender, EventArgs e)
		{
			if (txtFilter.Text == "关键字过滤（逗号分隔）")
			{
				txtFilter.Text = "";
				txtFilter.ForeColor = System.Drawing.Color.Black;
			}
		}

		private void txtFilter_Leave(object sender, EventArgs e)
		{
			if (string.IsNullOrEmpty(txtFilter.Text))
			{
				txtFilter.Text = "关键字过滤（逗号分隔）";
				txtFilter.ForeColor = System.Drawing.Color.Gray;
			}
		}

		private void lvFiles_ColumnClick(object sender, ColumnClickEventArgs e)
		{
			switch (e.Column)
			{
				case 0: ToggleSort("Name"); break;
				case 1: ToggleSort("Size"); break;
				case 2: ToggleSort("Modified"); break;
			}
			ApplyFilterAndRender();
		}

		private void miOpenFile_Click(object sender, EventArgs e)
		{
			if (lvFiles.SelectedItems.Count == 0) return;
			var path = lvFiles.SelectedItems[0].Tag as string;
			try
			{
				Process.Start(path);
			}
			catch (Exception ex)
			{
				MessageBox.Show(this, ex.Message, "打开文件失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		private void miOpenFolder_Click(object sender, EventArgs e)
		{
			if (lvFiles.SelectedItems.Count == 0) return;
			var path = lvFiles.SelectedItems[0].Tag as string;
			try
			{
				var args = "/select, \"" + path + "\"";
				Process.Start("explorer.exe", args);
			}
			catch (Exception ex)
			{
				MessageBox.Show(this, ex.Message, "打开目录失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		private void ResetUiAfterFinish()
		{
			btnStart.Enabled = true;
			btnStop.Enabled = false;
			progress.Visible = false;
			if (lblStatus.Text == "正在扫描...已找到 0 个文件" || lblStatus.Text.StartsWith("正在扫描..."))
			{
				lblStatus.Text = "就绪";
			}
		}

		private void ToggleSort(string key)
		{
			if (_currentSort == key)
			{
				_sortAscending = !_sortAscending;
			}
			else
			{
				_currentSort = key;
				_sortAscending = true;
			}
		}

		private async Task ScanDirectoryAsync(string root, CancellationToken token)
		{
			var stack = new Stack<string>();
			stack.Push(root);
			int lastUpdateCount = 0;
			
			while (stack.Count > 0)
			{
				token.ThrowIfCancellationRequested();
				
				var current = stack.Pop();
				string[] dirs;
				try { dirs = Directory.GetDirectories(current); }
				catch (UnauthorizedAccessException) 
				{ 
					Interlocked.Increment(ref _accessDeniedCount);
					continue; 
				}
				catch (Exception) 
				{ 
					Interlocked.Increment(ref _otherErrorCount);
					continue; 
				}
				for (int i = 0; i < dirs.Length; i++) stack.Push(dirs[i]);

				string[] files;
				try { files = Directory.GetFiles(current); }
				catch (UnauthorizedAccessException) 
				{ 
					Interlocked.Increment(ref _accessDeniedCount);
					continue; 
				}
				catch (Exception) 
				{ 
					Interlocked.Increment(ref _otherErrorCount);
					continue; 
				}
				
				for (int i = 0; i < files.Length; i++)
				{
					token.ThrowIfCancellationRequested();
					
					// 检查文件数量限制
					lock (_lock)
					{
						if (_allFiles.Count >= MAX_FILES)
						{
							throw new InvalidOperationException($"文件数量超过限制！最大允许 {MAX_FILES} 个文件，当前已找到 {_allFiles.Count} 个文件。请选择包含文件较少的目录。");
						}
					}
					
					var path = files[i];
					FileInfo fi;
					try { fi = new FileInfo(path); }
					catch { continue; }
					
					var item = new FileItem();
					item.FullPath = path;
					item.Size = fi.Exists ? fi.Length : 0;
					item.Modified = fi.Exists ? fi.LastWriteTime : DateTime.MinValue;
					item.Extension = (fi.Extension ?? string.Empty).ToLowerInvariant();

					lock (_lock) { _allFiles.Add(item); }

					// 减少UI更新频率，每100个文件更新一次
					if (_allFiles.Count - lastUpdateCount >= 100)
					{
						lastUpdateCount = _allFiles.Count;
						this.Invoke(new Action(delegate
						{
							lblStatus.Text = "正在扫描...已找到 " + _allFiles.Count + " 个文件";
							ApplyFilterAndRenderPartial();
						}));
						
						// 让出控制权，避免阻塞UI
						await Task.Yield();
					}
				}
			}
		}

		private void ApplyFilterAndRender()
		{
			List<FileItem> snapshot;
			lock (_lock) { snapshot = new List<FileItem>(_allFiles); }
			var filtered = ApplyKeywordFilter(snapshot, txtFilter.Text);
			RenderList(filtered);
			RenderStatsAndChart(filtered);
		}

		private void ApplyFilterAndRenderPartial()
		{
			List<FileItem> snapshot;
			lock (_lock) { snapshot = new List<FileItem>(_allFiles); }
			var filtered = ApplyKeywordFilter(snapshot, txtFilter.Text);
			RenderList(filtered, true);
			RenderStatsAndChart(filtered);
		}

		private List<FileItem> ApplyKeywordFilter(List<FileItem> items, string keywords)
		{
			if (string.IsNullOrEmpty(keywords) || keywords == "关键字过滤（逗号分隔）") return Sort(items);
			var tokens = keywords.Split(new char[] { ',', ' ', ';', '|' }, StringSplitOptions.RemoveEmptyEntries);
			if (tokens.Length == 0) return Sort(items);
			var lowered = new List<string>();
			for (int i = 0; i < tokens.Length; i++) lowered.Add(tokens[i].ToLowerInvariant());
			var result = new List<FileItem>();
			for (int i = 0; i < items.Count; i++)
			{
				var path = items[i].FullPath.ToLowerInvariant();
				bool match = false;
				for (int j = 0; j < lowered.Count; j++)
				{
					if (path.IndexOf(lowered[j]) >= 0) { match = true; break; }
				}
				if (match) result.Add(items[i]);
			}
			return Sort(result);
		}

		private List<FileItem> Sort(List<FileItem> items)
		{
			Comparison<FileItem> cmp;
			switch (_currentSort)
			{
				case "Size": 
					cmp = delegate(FileItem a, FileItem b) { return a.Size.CompareTo(b.Size); }; 
					break;
				case "Modified": 
					cmp = delegate(FileItem a, FileItem b) { return a.Modified.CompareTo(b.Modified); }; 
					break;
				default: // Name - 按文件类型分组，然后按文件名排序
					cmp = delegate(FileItem a, FileItem b) 
					{
						// 首先按扩展名排序
						int extCompare = string.Compare(a.Extension, b.Extension, StringComparison.OrdinalIgnoreCase);
						if (extCompare != 0) return extCompare;
						
						// 扩展名相同时，按文件名排序
						string nameA = System.IO.Path.GetFileName(a.FullPath);
						string nameB = System.IO.Path.GetFileName(b.FullPath);
						return string.Compare(nameA, nameB, StringComparison.OrdinalIgnoreCase);
					}; 
					break;
			}
			items.Sort(cmp);
			if (!_sortAscending) items.Reverse();
			return items;
		}

		private void RenderList(List<FileItem> items)
		{
			RenderList(items, false);
		}

		private void RenderList(List<FileItem> items, bool partial)
		{
			lvFiles.BeginUpdate();
			try
			{
				if (!partial) lvFiles.Items.Clear();
				int existing = partial ? lvFiles.Items.Count : 0;
				for (int i = existing; i < items.Count; i++)
				{
					var it = items[i];
					var lvi = new ListViewItem(it.FullPath);
					lvi.SubItems.Add(FormatSize(it.Size));
					lvi.SubItems.Add(it.Modified.ToString("yyyy-MM-dd HH:mm:ss"));
					lvi.Tag = it.FullPath;
					lvFiles.Items.Add(lvi);
				}
			}
			finally
			{
				lvFiles.EndUpdate();
			}
		}

		private void RenderStatsAndChart(List<FileItem> items)
		{
			var dict = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
			for (int i = 0; i < items.Count; i++)
			{
				var ext = items[i].Extension;
				if (string.IsNullOrEmpty(ext)) ext = "(无扩展名)";
				int count;
				if (!dict.TryGetValue(ext, out count)) count = 0;
				dict[ext] = count + 1;
			}

			lvStats.BeginUpdate();
			try
			{
				lvStats.Items.Clear();
				int total2 = items.Count;
				int topItems = Math.Min(dict.Count, 15); // 最多显示15个项目
				int current = 0;
				int otherCount = 0;

				foreach (var kv in dict.OrderByDescending(delegate(KeyValuePair<string, int> p) { return p.Value; }))
				{
					if (current < topItems)
					{
						var lvi = new ListViewItem(kv.Key);
						lvi.SubItems.Add(kv.Value.ToString("N0")); // 添加千位分隔符
						string percent = total2 > 0 ? ((kv.Value * 100.0) / total2).ToString("0.##") : "0";
						lvi.SubItems.Add(percent);

						// 根据文件数量设置不同的字体样式
						//if (current < 3) // 前3项使用粗体
						//{
						//	//lvi.Font = new System.Drawing.Font(lvi.Font, System.Drawing.FontStyle.Bold);
						//}
						lvStats.Items.Add(lvi);
						current++;
					}
					else
					{
						otherCount += kv.Value;
					}
				}

				// 如果有超过topItems的项目，添加"其他"项
				if (dict.Count > topItems)
				{
					var lviOther = new ListViewItem("(其他类型)");
					lviOther.SubItems.Add(otherCount.ToString("N0"));
					string percentOther = total2 > 0 ? ((otherCount * 100.0) / total2).ToString("0.##") : "0";
					lviOther.SubItems.Add(percentOther);
					lviOther.ForeColor = System.Drawing.Color.Gray;
					lvStats.Items.Add(lviOther);
				}

				// 添加总计行
				if (items.Count > 0)
				{
					var lviTotal = new ListViewItem("总计");
					lviTotal.SubItems.Add(total2.ToString("N0"));
					lviTotal.SubItems.Add("100");
					lviTotal.BackColor = System.Drawing.Color.FromArgb(220, 220, 220);
					lviTotal.Font = new System.Drawing.Font(lviTotal.Font, System.Drawing.FontStyle.Bold);
					lvStats.Items.Add(lviTotal);
				}
			}
			finally
			{
				lvStats.EndUpdate();
			}

			var series = chartTypes.Series[0];
			series.Points.Clear();
			series["PieLabelStyle"] = "Outside";
			series["PieLineColor"] = "Black";
			int total = items.Count;
			foreach (var kv in dict.OrderByDescending(delegate(KeyValuePair<string, int> p) { return p.Value; }))
			{
				int pointIndex = series.Points.AddXY(kv.Key, kv.Value);
				string percent = total > 0 ? ((kv.Value * 100.0) / total).ToString("0.##") : "0";
				series.Points[pointIndex].Label = kv.Key + "\n" + percent + "%";
				series.Points[pointIndex].Font = new System.Drawing.Font("Microsoft YaHei", 8);
				series.Points[pointIndex].LabelForeColor = System.Drawing.Color.Black;
			}
		}

		private static string FormatSize(long size)
		{
			double s = size;
			string[] units = new string[] { "B", "KB", "MB", "GB", "TB" };
			int idx = 0;
			while (s >= 1024 && idx < units.Length - 1)
			{
				s = s / 1024.0;
				idx++;
			}
			return s.ToString("0.##") + " " + units[idx];
		}

		// 获取友好的错误消息
		private string GetFriendlyErrorMessage(Exception ex)
		{
			if (ex is UnauthorizedAccessException)
			{
				return "无法访问指定目录。请检查您是否有足够的权限，或者尝试以管理员身份运行程序。";
			}
			else if (ex is PathTooLongException)
			{
				return "文件路径过长，无法访问。Windows系统对文件路径长度有限制。";
			}
			else if (ex is IOException)
			{
				return "I/O错误：" + ex.Message + "\n\n请确保您正在访问的文件或目录没有被其他程序锁定。";
			}
			else if (ex is InvalidOperationException && ex.Message.Contains("文件数量超过限制"))
			{
				return ex.Message;
			}
			else
			{
				return "扫描过程中发生错误：" + ex.Message + "\n\n如果问题持续存在，请联系技术支持。";
			}
		}

		private class FileItem
		{
			public string FullPath;
			public long Size;
			public DateTime Modified;
			public string Extension;
		}
	}
}